package utils;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;


import dtos.TechresourceDTO;
import model.Domain;
import model.Domain_;
import model.Techresource;
import model.Techresource_;


/**
 * Session Bean implementation class TechresourceDAO
 * @author Radulescu Cristina
 * @author Pop Loredana
 */
/**
 * @author Pop Loredana
 * @author Radulescu Cristina
 *
 */
@Stateless
@LocalBean
public class TechresourceDAO implements TechresourceDAORemote {

	/**
	 * Default constructor.
	 */
	public TechresourceDAO() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * Default constructor.
	 */

	@PersistenceContext
	EntityManager em;

	@EJB
	Conv conv;

	/**
	 * Method used to get all techresources by domain id
	 * @param id
	 * @return list of techresources
	 */
	@Override
	public List<TechresourceDTO> getTechResourcesDTOByDomainId(int id) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);
		

		Join<Techresource, Domain> domain = resources
				.join(Techresource_.domain);
		cq.select(resources);
		cq.where(cb.equal(domain.get(Domain_.id), id));
		List<Techresource> resourcesList = em.createQuery(cq).getResultList();
		List<TechresourceDTO> resourcesDTO = new ArrayList<>();
		
		for (Techresource t : resourcesList) {
			resourcesDTO.add(conv.fromEntityTechresource(t));
		}
		return resourcesDTO;
	}

	/**
	 * Method used to get techresources by id
	 * @param id
	 * @return techresource
	 */
	@Override
	public TechresourceDTO getTechresourcesById(int id) {
		Techresource t = em.find(Techresource.class, id);
		return conv.fromEntityTechresource(t);
	}

	/**
	 * Method used to insert techresource 
	 * @param tech of type Techresource
	 */
	@Override
	public void insertTechresource(TechresourceDTO tech) {
		Domain d = em.find(Domain.class, tech.getIdDomain());
		Techresource t = em.find(Techresource.class, tech.getId());

		if (t == null) {
			Techresource d1 = conv.fromEntityTechresourceDTO(tech);
			d1.setDomain(d);
			em.persist(d1);
		} else {
			t.setDomain(d);
			em.merge(t);
		}

	}

	/**
	 * Method used to get all techresourcesDto by ip
	 * @param ip
	 * @return list of techresources
	 */
	@Override
	public List<TechresourceDTO> getTechResourcesDTOByIp(String ip) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);

		cq.select(resources);
		
		cq.where(cb.equal(resources.get("ip"), ip));

		List<Techresource> resourcesList = em.createQuery(cq).getResultList();
		List<TechresourceDTO> resourcesDTO = new ArrayList<>();

		for (Techresource t : resourcesList) {
			resourcesDTO.add(conv.fromEntityTechresource(t));
		}
		return resourcesDTO;
	}

	/**
	 * Method used to get techresource by ip
	 * @param ip
	 * @return techresource
	 */
	@Override
	public TechresourceDTO getTechResourceDTOByIp(String ip) {

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);
		cq.select(resources).where(cb.equal(resources.get("ip"), ip));

		Techresource t = em.createQuery(cq).getSingleResult();

		return conv.fromEntityTechresource(t);

	}

	/**
	 * Method used to get all techresources
	 * @return list of techresources
	 */
	@Override
	public List<TechresourceDTO> getAllTechresources() {
		List<TechresourceDTO> resultlist = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resp = cq.from(Techresource.class);
		cq.select(resp);

		TypedQuery<Techresource> q = em.createQuery(cq);

		List<Techresource> responses = q.getResultList();

		for (Techresource d : responses) {
			resultlist.add(conv.fromEntityTechresource(d));
		}

		return resultlist;
	}

	/**
	 * Method used to get all techresources by name
	 * @return list of techresourceDto
	 * @param name
	 */
	@Override
	public List<TechresourceDTO> getAllTechresourcesByName(String name) {
		List<TechresourceDTO> resultlist = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resp = cq.from(Techresource.class);
		cq.select(resp);

		TypedQuery<Techresource> q = em.createQuery(cq);

		List<Techresource> responses = q.getResultList();

		for (Techresource d : responses) {
			if (d.getName().equals(name))
				resultlist.add(conv.fromEntityTechresource(d));
		}

		return resultlist;
	}

	/**
	 * Method used to delete Techresource
	 * @param techresource
	 */
	@Override
	public void deleteTechresource(TechresourceDTO ud) {
		Techresource r = em.find(Techresource.class, ud.getId());
		em.remove(r);
	}

	/**
	 * Method used to get all techresources by name
	 * @param name
	 * @return list of techresources
	 */
	@Override
	public List<TechresourceDTO> getTechresourcesByName(String name) {
		List<TechresourceDTO> results = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		EntityType<Techresource> type = em.getMetamodel().entity(
				Techresource.class);
		Root<Techresource> res = cq.from(Techresource.class);
		cq.select(res).where(
				cb.like(res.get(type.getDeclaredSingularAttribute("name",
						String.class)), "%" + name + "%"));

		TypedQuery<Techresource> q = em.createQuery(cq);
		List<Techresource> resour = q.getResultList();
		for (Techresource u : resour) {
			results.add(conv.fromEntityTechresource(u));
		}
		return results;
	}

	/**
	 * Method used to get all printer ips
	 * @return list of strings
	 */
	@Override
	public List<String> getAllPrinterIps() {
		List<String> ips = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		EntityType<Techresource> type = em.getMetamodel().entity(
				Techresource.class);
		Root<Techresource> res = cq.from(Techresource.class);
		cq.select(res).where(
				cb.like(res.get(type.getDeclaredSingularAttribute("name",
						String.class)), "%Printer%"));
		TypedQuery<Techresource> q = em.createQuery(cq);
		List<Techresource> resour = q.getResultList();
		for (Techresource u : resour) {
			ips.add(u.getIp());
		}
		return ips;
	}

	/**
	 * Method used to update techresource
	 * @param techresource
	 */
	@Override
	public void updateTechresource(TechresourceDTO tech) {
		Domain d = em.find(Domain.class, tech.getIdDomain());
		Techresource t = em.find(Techresource.class, tech.getId());

		if (t == null) {
			Techresource d1 = conv.fromEntityTechresourceDTO(tech);
			d1.setDomain(d);
			em.persist(d1);
		} else {
			t.setIdnumber(tech.getIdnumber());
			t.setStatus(tech.getStatus());
			t.setDomain(d);
			t.setIp(tech.getIp());
			t.setName(tech.getName());
			em.merge(t);
		}

	}

	/**
	 * Method used to get techresources by printer domain
	 * @param id
	 * @return list of techresources
	 */
	@Override
	public List<TechresourceDTO> getTechResourcesDTOPrinterByDomainId(int id) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		EntityType<Techresource> type = em.getMetamodel().entity(
				Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);
		cq.select(resources).where(
				cb.like(resources.get(type.getDeclaredSingularAttribute("name",
						String.class)), "%Printer%"));
		List<Techresource> resourcesList = em.createQuery(cq).getResultList();
		List<TechresourceDTO> resourcesDTO = new ArrayList<>();

		for (Techresource t : resourcesList) {
			if (t.getDomain().getId() == id)
				resourcesDTO.add(conv.fromEntityTechresource(t));
		}
		return resourcesDTO;
	}
	
	@Override
	public List<TechresourceDTO> getTechResourcesDTOPrinters() {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		EntityType<Techresource> type = em.getMetamodel().entity(
				Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);
		cq.select(resources).where(
				cb.like(resources.get(type.getDeclaredSingularAttribute("name",
						String.class)), "%Printer%"));
		List<Techresource> resourcesList = em.createQuery(cq).getResultList();
		List<TechresourceDTO> resourcesDTO = new ArrayList<>();

		for (Techresource t : resourcesList) {
				resourcesDTO.add(conv.fromEntityTechresource(t));
		}
		return resourcesDTO;
	}
	
    /**
     * Method used to set the domain at null by id
     * @param idDomain
     */
	@Override
	public void setDomainNullByDomainId(int idDomain) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techresource> cq = cb.createQuery(Techresource.class);
		Root<Techresource> resources = cq.from(Techresource.class);
		cq.select(resources);
		List<Techresource> resourcesList = em.createQuery(cq).getResultList();
		
		for (Techresource t : resourcesList) {
			if (t.getDomain() != null && t.getDomain().getId() == idDomain) {
				if(em.find(Techresource.class, t.getId())!=null) {
					t.setDomain(null);
					em.merge(t);
				}
			}
				
		}
	}
	
	
}
